#include "napi/native_api.h"
#include "hilog/log.h"
#include <js_native_api.h>
#include <js_native_api_types.h>
#include <string.h>
#include "./common.h"
#include <string>
static napi_value createObject(napi_env env, napi_callback_info info)
{
    size_t requireArgc = 1;
    size_t argc = 1;
    napi_value args[1] = { nullptr };
    
    napi_value obj;
    napi_create_object(env, &obj);
    
    napi_value world;
    napi_create_string_utf8(env, "world", NAPI_AUTO_LENGTH, &world);
    
    napi_value arr, arrElement0, arrElement1, arrElement2;
    napi_create_array(env, &arr);
   
    napi_create_int32(env, 94, &arrElement0);
    napi_set_element(env, arr, 0, arrElement0);
   
    napi_create_string_utf8(env, "123d", NAPI_AUTO_LENGTH, &arrElement1);
    napi_set_element(env, arr, 1, arrElement1);
   
    napi_create_double(env, 12.32, &arrElement2);
    napi_set_element(env, arr, 2, arrElement2);
    
    napi_value obj1, objValue;
    napi_create_object(env, &obj1);
  
    napi_create_string_utf8(env, "obj in obj", NAPI_AUTO_LENGTH, &objValue);
    napi_set_named_property(env, obj1, "test", objValue);
    
    napi_set_named_property(env, obj, "hello", world);
    napi_set_named_property(env, obj, "arr", arr);
    napi_set_named_property(env, obj, "obj1", obj1);
    
    return obj;
}

static napi_value modifyObject(napi_env env, napi_callback_info info) {
    size_t requireArgc = 1;
    size_t argc = 1;
    napi_value args[1] = { nullptr };
    
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    napi_value obj = args[0];
    napi_value world0;
    napi_create_string_utf8(env, "world0", NAPI_AUTO_LENGTH, &world0);
    napi_set_named_property(env, obj, "hello", world0);
    
    napi_value arr;
    napi_get_named_property(env, obj, "arr", &arr);
    napi_delete_element(env, arr, 2, nullptr);
    
    uint32_t arrLen;
    napi_get_array_length(env, arr, &arrLen);
    
    uint32_t i = 0;
    for(i = 0; i < arrLen; i++) {
        napi_value tmp;
        napi_create_uint32(env, i, &tmp);
        napi_set_element(env, arr, i, tmp);
    }
    
    napi_value typedArr;
    napi_get_named_property(env, obj, "typedArray", &typedArr);
    bool is_typedarray;
    NODE_API_CALL(env, napi_is_typedarray(env, typedArr, &is_typedarray));
    
    napi_typedarray_type type;
    napi_value input_buffer;
    size_t byte_offset;
    size_t length;
    NODE_API_CALL(env, napi_get_typedarray_info(env, typedArr, &type, &length, NULL, &input_buffer, &byte_offset));
    
    void* data;
    size_t byte_length;
    NODE_API_CALL(env, napi_get_arraybuffer_info(env, input_buffer, &data, &byte_length));
    
    napi_value output_buffer;
    void* output_ptr;
    NODE_API_CALL(env, napi_create_arraybuffer(env, byte_length, &output_ptr, &output_buffer));
    
    napi_value output_array;
    NODE_API_CALL(env, napi_create_typedarray(env, type, length, output_buffer, byte_offset, &output_array));
    
    uint8_t* input_bytes = (uint8_t*)(data) + byte_offset;
    uint8_t* output_bytes = (uint8_t*)(output_ptr);
    for (i = 0; i < length; i++) {
        output_bytes[i] = (uint8_t)(input_bytes[i] * 2);
    }
    napi_set_named_property(env, obj, "typedArray", output_array);
    
    napi_value obj1;
    NODE_API_CALL(env, napi_get_named_property(env, obj, "obj1", &obj1));
    
    napi_value str;
    NODE_API_CALL(env, napi_get_named_property(env, obj1, "test", &str));
    
    char buf;
    size_t bufSize = 20;
    size_t res;
    NODE_API_CALL(env, napi_get_value_string_utf8(env, str, &buf, bufSize, &res));
    strcat(&buf, "，this is be modified");

    napi_value newNapiStr;
    napi_create_string_utf8(env, &buf, NAPI_AUTO_LENGTH, &newNapiStr);
    napi_set_named_property(env, obj1, "test", newNapiStr);

    napi_set_named_property(env, obj, "obj1", obj1);
    return obj;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        { "createObject", nullptr, createObject, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "modifyObject", nullptr, modifyObject, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version =1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&demoModule);
}